#pragma once

#include "QueryEvaluator.h"

QueryEvaluator::QueryEvaluator(PKB* pkb) {
	myPKB = pkb;
};

class myexceptionQ: public exception {
	virtual const char* what() const throw() {
		return "Syntax error in PQL";
	}
} myexQE;

class rubbishWith: public exception {
	virtual const char* what() const throw() {
		return "You are a loser";
	}
} rubbishWithException;

class firstParaminModifiesUnderscoreException: public exception {
	virtual const char* what() const throw() {
		return "First parameter of Modifies cannot be underscore";
	}
} firstParaminModifiesUnderscoreException;

class firstParaminUsesUnderscoreException: public exception {
	virtual const char* what() const throw() {
		return "First parameter Uses cannot be underscore";
	}
} firstParaminUsesUnderscoreException;

vector<string> QueryEvaluator::evaluate(vector< vector<string> > result) 
{	
	initAnswer.clear();
	finalAnswer.clear();

	vector<string> orderEvaluation = result.at(result.size()-1);
	operand = result.at(0).at(0);
	operandType = result.at(0).at(1);
	string isCountLocal = result.at(0).at(2);
	vector<string> yoTuples;
	vector<string> yoTuplesOperand;
	yoTuples.clear();
	
	if(operandType=="tuple")
	{

		for(int i = 4; i < stoi(operand)*2+4; i++)
		{
			vector<NAME> z;
			string actualOperandType = result.at(0).at(i+1);
			z.push_back(result.at(0).at(i));
			yoTuples.push_back(result.at(0).at(i));
			yoTuplesOperand.push_back(result.at(0).at(i+1));			
			Schema x(1,z);
			++i;
			
			if (!(actualOperandType == "variable" || actualOperandType == "constant" || actualOperandType == "BOOLEAN")) {
			for (auto it = myPKB->stmtTable->stmtTable.begin(); it != myPKB->stmtTable->stmtTable.end(); ++it) {
				if ((it->second==actualOperandType) || (actualOperandType=="stmt") || (actualOperandType=="prog_line"))	{
					vector<INDEX> z;
					z.push_back(it->first);
					x.insertTuple(z);
				}
			}
			}

			if (actualOperandType == "variable") {
				for (auto it = myPKB->varTable->varTable.begin(); it != myPKB->varTable->varTable.end(); ++it) {
					vector<INDEX> z;
					z.push_back(it->first);
					x.insertTuple(z);
				}
			}

			if (actualOperandType == "constant") {
				for (auto it = myPKB->ast->constTable.begin(); it != myPKB->ast->constTable.end(); ++it) {
					vector<INDEX> z;
					z.push_back(*it);
					x.insertTuple(z);
				}
			}

			if (actualOperandType == "procedure") {
				for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) {
					vector<INDEX> z;
					z.push_back(it->first);
					x.insertTuple(z);
				}
			}
			
			if(i==5)
			{
				initAnswer.deepCopy(x);
			}
			else
			{
				initAnswer.naturalJoin(x);
			}
		}
	}
	else
	{
		vector<NAME> z;
		z.push_back(operand);
		Schema x(1,z);
		initAnswer.deepCopy(x);

		if (!(operandType == "variable" || operandType == "constant" || operandType == "BOOLEAN")) {
			for (auto it = myPKB->stmtTable->stmtTable.begin(); it != myPKB->stmtTable->stmtTable.end(); ++it) {
				if ((it->second==operandType) || (operandType=="stmt") || (operandType=="prog_line"))	{
					vector<INDEX> z;
					z.push_back(it->first);
					initAnswer.insertTuple(z);
				}
			}
		}

		if (operandType == "variable") {
			for (auto it = myPKB->varTable->varTable.begin(); it != myPKB->varTable->varTable.end(); ++it) {
				vector<INDEX> z;
				z.push_back(it->first);
				initAnswer.insertTuple(z);
			}
		}

		if (operandType == "constant") {
			for (auto it = myPKB->ast->constTable.begin(); it != myPKB->ast->constTable.end(); ++it) {
				vector<INDEX> z;
				z.push_back(*it);
				initAnswer.insertTuple(z);
			}
		}

		if (operandType == "procedure") {
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) {
				vector<INDEX> z;
				z.push_back(it->first);
				initAnswer.insertTuple(z);
			}
		}
	}

	set<string> final;
	

	if(result.size()==2)
	{
		finalAnswer.deepCopy(initAnswer);
	}
	
	for(int j = 0;j<orderEvaluation.size();j++)
	{
		cout << stoi(orderEvaluation.at(j)) << endl;
		int i = stoi(orderEvaluation.at(j));
		if(j==0)
		{
			if(result.at(i).at(0)=="such that")
			{
				finalAnswer.deepCopy(evaluateSuchThat(result.at(i)));
			}
			else if(result.at(i).at(0)=="pattern")
			{
				finalAnswer.deepCopy(evaluatePattern(result.at(i)));
			}
			else
			{
				finalAnswer.deepCopy(evaluateWith(result.at(i)));
			}
		}
		else
		{
			if(result.at(i).at(0)=="such that")
			{
				bool localBool = false;
				Schema s = evaluateSuchThat(result.at(i));
				finalAnswer.deepCopy(finalAnswer.naturalJoin(s));
				if(s.numRows==0){localBool = true;}
				s.clear();
				if(localBool){break;}
			}
			else if(result.at(i).at(0)=="pattern")
			{
				bool localBool = false;
				Schema s = evaluatePattern(result.at(i));
				finalAnswer.deepCopy(finalAnswer.naturalJoin(s));
				if(s.numRows==0){localBool = true;}
				s.clear();
				if(localBool){break;}
			}
			else
			{
				bool localBool = false;				
				Schema s = evaluateWith(result.at(i));
				finalAnswer.deepCopy(finalAnswer.naturalJoin(s));
				if(s.numRows==0){localBool = true;}
				s.clear();
				if(localBool){break;}
			}
		}
	}
	
	

		if(operand!="BOOLEAN")
		{
			if(operandType!="tuple")
			{
			
			finalAnswer.deepCopy(initAnswer.naturalJoin(finalAnswer));
			
			//-------------------------------------------------------------change here----------
			set<INDEX> lll = finalAnswer.project(operand);
			//hash_set<INDEX> lll = myPKB->result->bags.at(operand);
			//-----------------------------------------------------------------------
			if(isCountLocal=="COUNT")
			{
				int localCount = lll.size();
				char Result[16];
				sprintf_s(Result, "%d", localCount);
				final.insert(Result);
			}
			else {
			if(operandType == "variable")
			{
				for (auto it = lll.begin(); it != lll.end(); ++it) 
				{
					final.insert(myPKB->varTable->getVarName(*it));
				}
			}
			else if(operandType == "procedure")
			{
				for (auto it = lll.begin(); it != lll.end(); ++it) 
				{
					final.insert(myPKB->procTable->getProcName(*it));
				}
			}
			else
			{
				if(result.at(0).at(3)=="TRUE")
				{
					for (auto it = lll.begin(); it != lll.end(); ++it) 
					{
						final.insert(myPKB->procTable->getProcName(myPKB->calls->callsTableStmt.find(*it)->second));
					}
				}
				else
				{
					for (auto it = lll.begin(); it != lll.end(); ++it) 
					{
						char Result[16];
						sprintf_s(Result, "%d", *it);
						final.insert(Result);
					}
				}
			}
			}
			}
			else
			{				
				finalAnswer.deepCopy(initAnswer.naturalJoin(finalAnswer));
				for(int d = 0;d<finalAnswer.numRows;d++)
				{
					string TupleAnswer;
					TupleAnswer.clear();
					for(int f = 0;f<yoTuples.size();f++)
					{
						for(int e = 0;e<finalAnswer.attributeList.size();e++)
						{
							if(finalAnswer.attributeList.at(e)==yoTuples.at(f))
							{
								if(yoTuplesOperand.at(f) == "variable")
								{
									TupleAnswer.append(myPKB->varTable->getVarName(finalAnswer.attributeItems.at(d).at(finalAnswer.someMap.at(finalAnswer.attributeList.at(e)))));
								}
								else if(yoTuplesOperand.at(f) == "procedure")
								{
									TupleAnswer.append(myPKB->procTable->getProcName(finalAnswer.attributeItems.at(d).at(finalAnswer.someMap.at(finalAnswer.attributeList.at(e)))));
								}
								else
								{
									/*if(result.at(0).at(3)=="TRUE")
									{
										for (auto it = lll.begin(); it != lll.end(); ++it) 
										{
											final.insert(myPKB->procTable->getProcName(myPKB->calls->callsTableStmt.find(*it)->second));
										}
									}*/
										char Result[16];
										sprintf_s(Result, "%d", finalAnswer.attributeItems.at(d).at(finalAnswer.someMap.at(finalAnswer.attributeList.at(e))));
										TupleAnswer.append(Result);
								}
							}
						}
						if(f!=yoTuples.size()-1)
						{
							TupleAnswer.append(" ");
						}

					}
					final.insert(TupleAnswer);
				}
			}
		}
		else
		{
			if(finalAnswer.numRows==0)
			{
				final.insert("false");
			}
			else
			{
				final.insert("true");
			}
		}
		vector<string> finalVectorized;
		
		for (auto it = final.begin(); it != final.end(); ++it) 
		{
			finalVectorized.push_back(*it);
		}

		return finalVectorized;
};

bool QueryEvaluator::validateNAME(string str) {
	if (!isalpha(str[0])) {
		throw myexQE;
	}

	for (int i = 0; i < (signed)str.length(); i++) {
		if (!isalnum(str[i])) {
			throw myexQE;
		}
	}
};

bool QueryEvaluator::match(string str, string ref) {
	if (str == ref) {
		return true;
	} else {
		throw myexQE;
	}
};

bool QueryEvaluator::match(string str, string ref, string ref2) {
	if (str == ref || str == ref2) {
		return true;
	} else {
		throw myexQE;
	}
};

bool QueryEvaluator::validateNAMEINTEGER(string str) {
	if (!isalpha(str[0])) {
		stoi(str);
	}

	for (int i = 0; i < (signed)str.length(); i++) {
		if (!isalnum(str[i])) {
			throw myexQE;
		}
	}
};

bool QueryEvaluator::hasEndsWith(string str, char ref) {
	if (str.back() == ref) {
		return true;
	} else {
		return false;
	}
};

bool QueryEvaluator::checkNAME(string str) { 
	if (!isalpha(str[0])) {
		return false;
	}
	for (int i = 0; i < (signed)str.length(); i++) {
		if (!isalnum(str[i])) {
			return false;
		}
	}
};

Schema QueryEvaluator::evaluateWith(vector<string> result) {
	string LHSFirst = result.at(1);
	string LHSType = result.at(2);
	string RHSFirst = result.at(3);
	string RHSType = result.at(4);
	if(LHSType=="string")
	{
		if(RHSType=="string")
		{
			vector<NAME> p;
			p.push_back("_");
			Schema xx(1,p);
			if(RHSFirst==LHSFirst)
			{
				vector<INDEX> vect;
				vect.push_back(-1);
				xx.insertTuple(vect);
			}
			else
			{
			}
			return xx;
		}
		else if(RHSType=="integer")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="procedure")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="call")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="variable")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="constant")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="stmt"||RHSType=="assign"||RHSType=="calls"||RHSType=="if"||RHSType=="while")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
	}
	else if(LHSType=="integer")
	{
		if(RHSType=="string")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="integer")
		{
			vector<NAME> p;
			p.push_back("_");
			Schema xx(1,p);
			if(LHSFirst==RHSFirst)
			{
				vector<INDEX> vect;
				vect.push_back(-1);
				xx.insertTuple(vect);
			}
			
			return xx;
		}
		else if(RHSType=="procedure")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="call")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="variable")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="constant")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="stmt"||RHSType=="assign"||RHSType=="calls"||RHSType=="if"||RHSType=="while")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
	}
	else if(LHSType=="procedure")
	{
		if(RHSType=="string")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="integer")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="procedure")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="call")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="variable")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="constant")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="stmt"||RHSType=="assign"||RHSType=="calls"||RHSType=="if"||RHSType=="while")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
	}
	else if(LHSType=="call")
	{
		if(RHSType=="string")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="integer")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="procedure")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="call")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="variable")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="constant")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="stmt"||RHSType=="assign"||RHSType=="calls"||RHSType=="if"||RHSType=="while")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
	}
	else if(LHSType=="variable")
	{
		if(RHSType=="string")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->varTable->varTable.begin(); it != myPKB->varTable->varTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;

		}
		else if(RHSType=="integer")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="procedure")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			p.push_back(RHSFirst);
			Schema xx(2,p);
			for (auto it = myPKB->varTable->varTable.begin(); it != myPKB->varTable->varTable.end(); ++it) 
			{
				for (auto it2 = myPKB->procTable->procTable.begin(); it2 != myPKB->procTable->procTable.end(); ++it2)
				{
					if(it->second==it2->second)
					{
						vector<INDEX> vect;
						vect.push_back(it->first);
						vect.push_back(it->first);
						xx.insertTuple(vect);
					}
				}
			}
			return xx;
		}
		else if(RHSType=="call")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="variable")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="constant")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="stmt"||RHSType=="assign"||RHSType=="calls"||RHSType=="if"||RHSType=="while")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
	}
	else if(LHSType=="constant")
	{
		if(RHSType=="string")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="integer")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->ast->constTable.begin(); it != myPKB->ast->constTable.end(); ++it) 
			{
				if(*it==stoi(RHSFirst))
				{
					vector<INDEX> vect;
					vect.push_back(*it);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="procedure")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="call")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			p.push_back(RHSFirst);
			Schema xx(2,p);
			for (auto it = myPKB->stmtTable->callsStmtTable.begin(); it != myPKB->stmtTable->callsStmtTable.end(); ++it) 
			{
				for (auto it2 = myPKB->ast->constTable.begin(); it2 != myPKB->ast->constTable.end(); ++it2) 
				{
					if(it->first==*it2)
					{
						vector<INDEX> vect;
						vect.push_back(*it2);
						vect.push_back(it->first);
						xx.insertTuple(vect);
					}
				}
			}
			return xx;
		}
		else if(RHSType=="variable")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="constant")
		{
			vector<NAME> p;
			p.push_back("_");
			Schema xx(1,p);
			
			if(!myPKB->ast->constTable.empty())
			{
				vector<INDEX> vect;
				vect.push_back(-1);
				xx.insertTuple(vect);
			}
			
			return xx;
		}
		else if(RHSType=="stmt"||RHSType=="assign"||RHSType=="calls"||RHSType=="if"||RHSType=="while")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			p.push_back(RHSFirst);
			Schema xx(2,p);
			for (auto it = myPKB->stmtTable->stmtTable.begin(); it != myPKB->stmtTable->stmtTable.end(); ++it) 
			{
				for (auto it2 = myPKB->ast->constTable.begin(); it2 != myPKB->ast->constTable.end(); ++it2) 
				{
					if(it->first==*it2)
					{
						vector<INDEX> vect;
						vect.push_back(*it2);
						vect.push_back(it->first);
						xx.insertTuple(vect);
					}
				}
			}
			return xx;
		}
	}
	else if(LHSType=="stmt"||LHSType=="assign"||LHSType=="calls"||LHSType=="if"||LHSType=="while")
	{	
		if(RHSType=="string")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="integer")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->stmtTable->stmtTable.begin(); it != myPKB->stmtTable->stmtTable.end(); ++it) 
			{
				if(it->first==stoi(RHSFirst)&&((LHSType=="stmt")||(LHSType==it->second)))
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="procedure")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="call")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="variable")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			Schema xx(1,p);
			for (auto it = myPKB->procTable->procTable.begin(); it != myPKB->procTable->procTable.end(); ++it) 
			{
				if(it->second==RHSFirst)
				{
					vector<INDEX> vect;
					vect.push_back(it->first);
					xx.insertTuple(vect);
				}
			}
			return xx;
		}
		else if(RHSType=="constant")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			p.push_back(RHSFirst);
			Schema xx(2,p);
			for (auto it = myPKB->stmtTable->stmtTable.begin(); it != myPKB->stmtTable->stmtTable.end(); ++it) 
			{
				for (auto it2 = myPKB->ast->constTable.begin(); it2 != myPKB->ast->constTable.end(); ++it2) 
				{
					if(it->first==*it2&&((it->second==LHSType)||(LHSType=="stmt")))
					{
						vector<INDEX> vect;
						vect.push_back(it->first);
						vect.push_back(*it2);
						xx.insertTuple(vect);
					}
				}
			}
			return xx;
		}
		else if(RHSType=="stmt"||RHSType=="assign"||RHSType=="calls"||RHSType=="if"||RHSType=="while")
		{
			vector<NAME> p;
			p.push_back(LHSFirst);
			p.push_back(RHSFirst);
			Schema xx(2,p);
			for (auto it = myPKB->stmtTable->stmtTable.begin(); it != myPKB->stmtTable->stmtTable.end(); ++it) 
			{
					vector<INDEX> vect;
					vect.push_back(it->first);
					vect.push_back(it->first);
					xx.insertTuple(vect);
			}
			return xx;
		}
	}
};

Schema QueryEvaluator::evaluateSuchThat(vector<string> result) {
	relationship = result.at(1);
	firstPara = result.at(2);
	secondPara = result.at(3);
	firstParaType = result.at(4);
	secondParaType = result.at(5);
	firstParamSynType = result.at(6);
	secondParamSynType = result.at(7);
	
	if (relationship == "Parent") {
		firstParamSynType = checkValidityOfParamStmtRef(firstParamSynType);
		secondParamSynType = checkValidityOfParamStmtRef(secondParamSynType);
		return evaluateParent();
	} else if (relationship == "Parent*") {
		firstParamSynType = checkValidityOfParamStmtRef(firstParamSynType);
		secondParamSynType = checkValidityOfParamStmtRef(secondParamSynType);
		return evaluateParentClosure();
	} else if (relationship == "Follows") {
		firstParamSynType = checkValidityOfParamStmtRef(firstParamSynType);
		secondParamSynType = checkValidityOfParamStmtRef(secondParamSynType);
		return evaluateFollows();
	} else if (relationship == "Follows*") {
		firstParamSynType = checkValidityOfParamStmtRef(firstParamSynType);
		secondParamSynType = checkValidityOfParamStmtRef(secondParamSynType);
		return evaluateFollowsClosure();
	} else if (relationship == "Calls") {
		return evaluateCalls();
	} else if (relationship == "Calls*") {
		return evaluateCallsClosure();
	} else if (relationship == "Next") {
		return evaluateNext();
	} else if (relationship == "Next*") {
		return evaluateNextClosure();
	} else if (relationship == "Affects") {
		return evaluateAffects();
	} else if (relationship == "Affects*") {
		return evaluateAffectsClosure();
	}
	else if (relationship == "Modifies") {
		firstParamSynType = checkValidityOfParamStmtRef(firstParamSynType);
		checkValidityOfParamEntRef(secondParamSynType);
		return evaluateModifies();
	} else if (relationship == "Uses") {
		firstParamSynType = checkValidityOfParamStmtRef(firstParamSynType);
		checkValidityOfParamEntRef(secondParamSynType);
		return evaluateUses();
	}
};

Schema QueryEvaluator::evaluatePattern(vector<string> result) {
	string patternOperandaa = result.at(1); 
	string opeType = result.at(2); 
	string LHS = result.at(3);
	string LHSType = result.at(4);
	string RHS = result.at(5);
	string RHSType = result.at(6);
	string assignIsSub = result.at(7);
	
	vector<string> RHSTokens;
	string cmpStr;

	if(opeType=="assign")
	{
			if (RHSType == "multiple") 
			{
					cmpStr = RHS;
			}			
			if (RHSType == "multiple" && LHSType == "syn") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				p.push_back(LHS);
				Schema xx(2,p);
				
				for (auto it = myPKB->stmtTable->patternTable.begin(); it != myPKB->stmtTable->patternTable.end(); ++it) 
				{	
					if(assignIsSub=="TRUE")
					{
						size_t found = it->second.find(cmpStr);
						if (found!=std::string::npos)
						{
							INDEX_SET temporada = myPKB->modifies->getModifiedByStmt(it->first);
							INDEX tempor;
							for (auto itz = temporada.begin(); itz != temporada.end(); ++itz) 
							{
								tempor = *itz;
								vector<INDEX> vec;
								vec.push_back(it->first);
								vec.push_back(*itz);
								xx.insertTuple(vec);
							}
						}
					}
					else
					{
						if (it->second==cmpStr)
						{
							INDEX_SET temporada = myPKB->modifies->getModifiedByStmt(it->first);
							INDEX tempor;
							for (auto itz = temporada.begin(); itz != temporada.end(); ++itz) 
							{
								tempor = *itz;
								vector<INDEX> vec;
								vec.push_back(it->first);
								vec.push_back(*itz);
								xx.insertTuple(vec);
							}
						}
					}
				}
				return xx;
			}

			if (RHSType == "multiple" && LHSType == "ident") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				Schema xx(1,p);

				for (auto it = myPKB->stmtTable->patternTable.begin(); it != myPKB->stmtTable->patternTable.end(); ++it) 
				{	
					if(assignIsSub=="TRUE")
					{
						size_t found = it->second.find(cmpStr);
						if (found!=std::string::npos)
						{
							INDEX_SET temporada = myPKB->modifies->getModifiedByStmt(it->first);
							for (auto itz = temporada.begin(); itz != temporada.end(); ++itz) 
							{
								if(myPKB->varTable->getVarName(*itz)==LHS)
								{
									vector<INDEX> vec;
									vec.push_back(it->first);
									xx.insertTuple(vec);
								}
							}
						}
					}
					else
					{
						if (it->second==cmpStr)
						{
							INDEX_SET temporada = myPKB->modifies->getModifiedByStmt(it->first);
							for (auto itz = temporada.begin(); itz != temporada.end(); ++itz) 
							{
								if(myPKB->varTable->getVarName(*itz)==LHS)
								{
									vector<INDEX> vec;
									vec.push_back(it->first);
									xx.insertTuple(vec);
								}
							}
						}
					}
				}
				return xx;
			}

			if (RHSType == "multiple" && LHSType == "underscore") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				Schema xx(1,p);

				for (auto it = myPKB->stmtTable->patternTable.begin(); it != myPKB->stmtTable->patternTable.end(); ++it) 
				{	
					if(assignIsSub=="TRUE")
					{
						size_t found = it->second.find(cmpStr);
						if (found!=std::string::npos)
						{
							vector<INDEX> vec;
							vec.push_back(it->first);
							xx.insertTuple(vec);
						}
					}
					else
					{
						if (it->second==cmpStr)
						{
							vector<INDEX> vec;
							vec.push_back(it->first);
							xx.insertTuple(vec);
						}
					}
				}
				return xx;
			}

			if (RHSType == "underscore" && LHSType == "syn") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				p.push_back(LHS);
				Schema xx(2,p);

				for (auto it = myPKB->stmtTable->patternTable.begin(); it != myPKB->stmtTable->patternTable.end(); ++it)
				{	
					INDEX_SET temporada = myPKB->modifies->getModifiedByStmt(it->first);
					INDEX tempor;
					for (auto itz = temporada.begin(); itz != temporada.end(); ++itz) 
					{
						tempor = *itz;
						vector<INDEX> vec;
						vec.push_back(it->first);
						vec.push_back(*itz);
						xx.insertTuple(vec);
					}
				}
				return xx;
			}

			if (RHSType == "underscore" && LHSType == "ident") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				Schema xx(1,p);

				for (auto it = myPKB->stmtTable->patternTable.begin(); it != myPKB->stmtTable->patternTable.end(); ++it) 
				{	
					INDEX_SET temporada = myPKB->modifies->getModifiedByStmt(it->first);
					for (auto itz = temporada.begin(); itz != temporada.end(); ++itz) 
					{
						if(myPKB->varTable->getVarName(*itz)==LHS)
						{
							vector<INDEX> vec;
							vec.push_back(it->first);
							xx.insertTuple(vec);
						}
					}
				}
				return xx;
			}

			if (RHSType == "underscore" && LHSType == "underscore") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				Schema xx(1,p);

				for (auto it = myPKB->stmtTable->patternTable.begin(); it != myPKB->stmtTable->patternTable.end(); ++it)
				{	
					vector<INDEX> vec;
					vec.push_back(it->first);
					xx.insertTuple(vec);		
				}
				return xx;
			}
		}
		else if(opeType=="while")
		{
			if (LHSType == "syn") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				p.push_back(LHS);
				Schema xx(2,p);

				for (auto it = myPKB->ast->whileStmtTable.begin(); it != myPKB->ast->whileStmtTable.end(); ++it) 
				{	
					if (myPKB->stmtTable->stmtTable.at(it->first)=="while") 
					{
						vector<INDEX> vec;
						vec.push_back(it->first);
						vec.push_back(it->second);
						xx.insertTuple(vec);
					}
				}
				return xx;
			}
			else if (LHSType == "ident") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				Schema xx(1,p);
				
				int varIndex = myPKB->varTable->getVarIndex(LHS);
				for (auto it = myPKB->ast->whileStmtTable.begin(); it != myPKB->ast->whileStmtTable.end(); ++it) 
				{	
					if (it->second == varIndex && myPKB->stmtTable->stmtTable.at(it->first)=="while") 
					{
						vector<INDEX> vec;
						vec.push_back(it->first);
						xx.insertTuple(vec);
					}
				}
				return xx;
			}
			else
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				Schema xx(1,p);
				
				for (auto it = myPKB->ast->whileStmtTable.begin(); it != myPKB->ast->whileStmtTable.end(); ++it) 
				{	
					if (myPKB->stmtTable->stmtTable.at(it->first)=="while") 
					{
						vector<INDEX> vec;
						vec.push_back(it->first);
						xx.insertTuple(vec);
					}
				}
				return xx;	
			}
		}
		else
		{
			if (LHSType == "syn") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				p.push_back(LHS);
				Schema xx(2,p);

				for (auto it = myPKB->ast->whileStmtTable.begin(); it != myPKB->ast->whileStmtTable.end(); ++it) 
				{	
					if (myPKB->stmtTable->stmtTable.at(it->first)=="if") 
					{
						vector<INDEX> vec;
						vec.push_back(it->first);
						vec.push_back(it->second);
						xx.insertTuple(vec);
					}
				}
				return xx;
			}
			else if (LHSType == "ident") 
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				Schema xx(1,p);
				
				int varIndex = myPKB->varTable->getVarIndex(LHS);
				for (auto it = myPKB->ast->whileStmtTable.begin(); it != myPKB->ast->whileStmtTable.end(); ++it) 
				{	
					if (it->second == varIndex && myPKB->stmtTable->stmtTable.at(it->first)=="if") 
					{
						vector<INDEX> vec;
						vec.push_back(it->first);
						xx.insertTuple(vec);
					}
				}
				return xx;
			}
			else
			{
				vector<NAME> p;
				p.push_back(patternOperandaa);
				Schema xx(1,p);
				
				for (auto it = myPKB->ast->whileStmtTable.begin(); it != myPKB->ast->whileStmtTable.end(); ++it) 
				{	
					if (myPKB->stmtTable->stmtTable.at(it->first)=="if") 
					{
						vector<INDEX> vec;
						vec.push_back(it->first);
						xx.insertTuple(vec);
					}
				}
				return xx;	
			}
		}
};

Schema QueryEvaluator::evaluateCalls() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->calls->getSynSyn(firstPara,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "ident") {
		return myPKB->calls->getSynIdent(firstPara,secondPara);	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->calls->getSynUnd(firstPara);	
	} else if (firstParaType == "ident" && secondParaType == "syn") {
		return myPKB->calls->getIdentSyn(firstPara,secondPara);
	} else if (firstParaType == "ident" && secondParaType == "ident") {
		return myPKB->calls->getIdentIdent(firstPara,secondPara);
	} else if (firstParaType == "ident" && secondParaType == "underscore") {
		return myPKB->calls->getIdentUnd(firstPara);
	} else if (firstParaType == "underscore" && secondParaType == "ident") {
		return myPKB->calls->getUndIdent(secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->calls->getUndSyn(secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->calls->getUndUnd();
	} 
};

Schema QueryEvaluator::evaluateCallsClosure() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->calls->getSynSynClosure(firstPara,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "ident") {
		return myPKB->calls->getSynIdentClosure(firstPara,secondPara);	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->calls->getSynUndClosure(firstPara);	
	} else if (firstParaType == "ident" && secondParaType == "syn") {
		return myPKB->calls->getIdentSynClosure(firstPara,secondPara);
	} else if (firstParaType == "ident" && secondParaType == "ident") {
		return myPKB->calls->getIdentIdentClosure(firstPara,secondPara);
	} else if (firstParaType == "ident" && secondParaType == "underscore") {
		return myPKB->calls->getIdentUndClosure(firstPara);
	} else if (firstParaType == "underscore" && secondParaType == "ident") {
		return myPKB->calls->getUndIdentClosure(secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->calls->getUndSynClosure(secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->calls->getUndUndClosure();
	} 
};

Schema QueryEvaluator::evaluateParent() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->parent->getSynSyn(firstParamSynType,firstPara,secondParamSynType,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "integer") {
		return myPKB->parent->getSynInt(firstParamSynType,firstPara,stoi(secondPara));	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->parent->getSynUnd(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {
		return myPKB->parent->getIntSyn(stoi(firstPara),secondParamSynType,secondPara);
	} else if (firstParaType == "integer" && secondParaType == "integer") {
		return myPKB->parent->getIntInt(stoi(firstPara),stoi(secondPara));
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->parent->getIntUnd(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "integer") {
		return myPKB->parent->getUndInt(stoi(secondPara));
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->parent->getUndSyn(secondParamSynType,secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->parent->getUndUnd();
	} 
};
Schema QueryEvaluator::evaluateParentClosure() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->parent->getSynSynClosure(firstParamSynType,firstPara,secondParamSynType,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "integer") {
		return myPKB->parent->getSynIntClosure(firstParamSynType,firstPara,stoi(secondPara));	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->parent->getSynUndClosure(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {
		return myPKB->parent->getIntSynClosure(stoi(firstPara),secondParamSynType,secondPara);
	} else if (firstParaType == "integer" && secondParaType == "integer") {
		return myPKB->parent->getIntIntClosure(stoi(firstPara),stoi(secondPara));
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->parent->getIntUndClosure(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "integer") {
		return myPKB->parent->getUndIntClosure(stoi(secondPara));
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->parent->getUndSynClosure(secondParamSynType,secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->parent->getUndUndClosure();
	} 
};

Schema QueryEvaluator::evaluateAffectsClosure() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->cfg->getSynSyn(firstParamSynType,firstPara,secondParamSynType,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "integer") {
		return myPKB->affects->getSynIntClosure(firstParamSynType,firstPara,stoi(secondPara));	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->cfg->getSynUnd(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {
		return myPKB->cfg->getIntSyn(stoi(firstPara),secondParamSynType,secondPara);
	} else if (firstParaType == "integer" && secondParaType == "integer") {
		return myPKB->cfg->getIntInt(stoi(firstPara),stoi(secondPara));
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->cfg->getIntUnd(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "integer") {
		return myPKB->cfg->getUndInt(stoi(secondPara));
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->cfg->getUndSyn(secondParamSynType,secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->cfg->getUndUnd();
	} 
};

Schema QueryEvaluator::evaluateAffects() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->cfg->getSynSyn(firstParamSynType,firstPara,secondParamSynType,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "integer") {
		return myPKB->affects->getSynInt(firstParamSynType,firstPara,stoi(secondPara));	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->cfg->getSynUnd(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {
		return myPKB->cfg->getIntSyn(stoi(firstPara),secondParamSynType,secondPara);
	} else if (firstParaType == "integer" && secondParaType == "integer") {
		return myPKB->cfg->getIntInt(stoi(firstPara),stoi(secondPara));
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->cfg->getIntUnd(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "integer") {
		return myPKB->cfg->getUndInt(stoi(secondPara));
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->cfg->getUndSyn(secondParamSynType,secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->cfg->getUndUnd();
	} 
};

Schema QueryEvaluator::evaluateNext() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->cfg->getSynSyn(firstParamSynType,firstPara,secondParamSynType,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "integer") {
		return myPKB->cfg->getSynInt(firstParamSynType,firstPara,stoi(secondPara));	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->cfg->getSynUnd(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {
		return myPKB->cfg->getIntSyn(stoi(firstPara),secondParamSynType,secondPara);
	} else if (firstParaType == "integer" && secondParaType == "integer") {
		return myPKB->cfg->getIntInt(stoi(firstPara),stoi(secondPara));
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->cfg->getIntUnd(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "integer") {
		return myPKB->cfg->getUndInt(stoi(secondPara));
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->cfg->getUndSyn(secondParamSynType,secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->cfg->getUndUnd();
	} 
};

Schema QueryEvaluator::evaluateNextClosure() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->cfg->getSynSyn(firstParamSynType,firstPara,secondParamSynType,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "integer") {
		return myPKB->cfg->getSynIntClosure(firstParamSynType,firstPara,stoi(secondPara));	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->cfg->getSynUnd(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {
		return myPKB->cfg->getIntSyn(stoi(firstPara),secondParamSynType,secondPara);
	} else if (firstParaType == "integer" && secondParaType == "integer") {
		return myPKB->cfg->getIntIntClosure(stoi(firstPara),stoi(secondPara));
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->cfg->getIntUnd(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "integer") {
		return myPKB->cfg->getUndInt(stoi(secondPara));
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->cfg->getUndSyn(secondParamSynType,secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->cfg->getUndUnd();
	} 
};

Schema QueryEvaluator::evaluateFollows() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->follows->getSynSyn(firstParamSynType,firstPara,secondParamSynType,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "integer") {
		return myPKB->follows->getSynInt(firstParamSynType,firstPara,stoi(secondPara));	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->follows->getSynUnd(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {
		return myPKB->follows->getIntSyn(stoi(firstPara),secondParamSynType,secondPara);
	} else if (firstParaType == "integer" && secondParaType == "integer") {
		return myPKB->follows->getIntInt(stoi(firstPara),stoi(secondPara));
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->follows->getIntUnd(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "integer") {
		return myPKB->follows->getUndInt(stoi(secondPara));
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->follows->getUndSyn(secondParamSynType,secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->follows->getUndUnd();
	} 
};

Schema QueryEvaluator::evaluateFollowsClosure() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->follows->getSynSynClosure(firstParamSynType,firstPara,secondParamSynType,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "integer") {
		return myPKB->follows->getSynIntClosure(firstParamSynType,firstPara,stoi(secondPara));	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->follows->getSynUndClosure(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {
		return myPKB->follows->getIntSynClosure(stoi(firstPara),secondParamSynType,secondPara);
	} else if (firstParaType == "integer" && secondParaType == "integer") {
		return myPKB->follows->getIntIntClosure(stoi(firstPara),stoi(secondPara));
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->follows->getIntUndClosure(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "integer") {
		return myPKB->follows->getUndIntClosure(stoi(secondPara));
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		return myPKB->follows->getUndSynClosure(secondParamSynType,secondPara);
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		return myPKB->follows->getUndUndClosure();
	} 
};

Schema QueryEvaluator::evaluateModifies() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->modifies->getSynSyn(firstParamSynType,firstPara,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "ident") {
		return myPKB->modifies->getSynIdent(firstParamSynType,firstPara,secondPara);	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->modifies->getSynUnd(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {//Select a such that Modifies (2,a)
		return myPKB->modifies->getIntSyn(stoi(firstPara),secondPara);
	} else if (firstParaType == "integer" && secondParaType == "ident") {
		return myPKB->modifies->getIntIdent(stoi(firstPara),secondPara);
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->modifies->getIntUnd(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "ident") {
		throw firstParaminModifiesUnderscoreException;
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		throw firstParaminModifiesUnderscoreException;
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		throw firstParaminModifiesUnderscoreException;
	} else if (firstParaType == "ident" && secondParaType == "ident") {
		return myPKB->modifies->getIdentIdent(firstPara,secondPara);
	} else if (firstParaType == "ident" && secondParaType == "syn") {
		return myPKB->modifies->getIdentSyn(firstPara,secondPara);
	} else if (firstParaType == "ident" && secondParaType == "underscore") {
		return myPKB->modifies->getIdentUnd(firstPara);
	} 
};

Schema QueryEvaluator::evaluateUses() {
	if (firstParaType == "syn" && secondParaType == "syn") {
		return myPKB->uses->getSynSyn(firstParamSynType,firstPara,secondPara);		
	} else if (firstParaType == "syn" && secondParaType == "ident") {
		return myPKB->uses->getSynIdent(firstParamSynType,firstPara,secondPara);	
	} else if (firstParaType == "syn" && secondParaType == "underscore") {
		return myPKB->uses->getSynUnd(firstParamSynType,firstPara);	
	} else if (firstParaType == "integer" && secondParaType == "syn") {//Select a such that Uses (2,a)
		return myPKB->uses->getIntSyn(stoi(firstPara),secondPara);
	} else if (firstParaType == "integer" && secondParaType == "ident") {
		return myPKB->uses->getIntIdent(stoi(firstPara),secondPara);
	} else if (firstParaType == "integer" && secondParaType == "underscore") {
		return myPKB->uses->getIntUnd(stoi(firstPara));
	} else if (firstParaType == "underscore" && secondParaType == "ident") {
		throw firstParaminUsesUnderscoreException;
	} else if (firstParaType == "underscore" && secondParaType == "syn") {
		throw firstParaminUsesUnderscoreException;
	} else if (firstParaType == "underscore" && secondParaType == "underscore") {
		throw firstParaminUsesUnderscoreException;
	} else if (firstParaType == "ident" && secondParaType == "ident") {
		return myPKB->uses->getIdentIdent(firstPara,secondPara);
	} else if (firstParaType == "ident" && secondParaType == "syn") {
		return myPKB->uses->getIdentSyn(firstPara,secondPara);
	} else if (firstParaType == "ident" && secondParaType == "underscore") {
		return myPKB->uses->getIdentUnd(firstPara);
	} 
};

string QueryEvaluator::checkValidityOfParamStmtRef(string paramSyn) {
	if (paramSyn == "variable" || paramSyn == "constant") {
		throw myexQE;
	} if (paramSyn == "prog_line") {
		return "stmt";
	} else {
		return paramSyn;
	}
};

void QueryEvaluator::checkValidityOfParamEntRef(string paramSyn) {
	if (!(paramSyn == "variable" || paramSyn == "NULL")) {
		throw myexQE;
	}
};